home *** CD-ROM | disk | FTP | other *** search
/ Creating Your Own America Online Web Pages / Creating Your Own America Online Web Pages.iso / TOOLS / TEX2RTF / SOURCES.ZIP / SRC / TEXUTILS.CC < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-18  |  36.0 KB  |  1,392 lines

  1. /*
  2.  * Miscellaneous utilities for manipulating LaTeX files and constructs
  3.  *
  4.  */
  5.  
  6. #include <wx.h>
  7. #include <wx_hash.h>
  8. #include <iostream.h>
  9. #include <fstream.h>
  10. #include <ctype.h>
  11. #include "tex2any.h"
  12.  
  13. wxHashTable TexReferences(wxKEY_STRING);
  14. wxList BibList(wxKEY_STRING);
  15. wxStringList CitationList;
  16. wxList ColourTable(wxKEY_STRING);
  17. wxHashTable BibStringTable(wxKEY_STRING);
  18. wxList CustomMacroList(wxKEY_STRING);
  19. TexChunk *currentSection = NULL;
  20. char *fakeCurrentSection = NULL;
  21.  
  22. static long BibLine = 1;
  23.  
  24. void OutputCurrentSection(void)
  25. {
  26.   if (currentSection)
  27.     TraverseChildrenFromChunk(currentSection);
  28.   else if (fakeCurrentSection)
  29.     TexOutput(fakeCurrentSection);
  30. }
  31.  
  32. // Called by Tex2Any to simulate a section
  33. void FakeCurrentSection(char *fakeSection, Bool addToContents)
  34. {
  35.   currentSection = NULL;
  36.   if (fakeCurrentSection) delete[] fakeCurrentSection;
  37.   fakeCurrentSection = copystring(fakeSection);
  38.  
  39.   if (DocumentStyle == LATEX_ARTICLE)
  40.   {
  41.     int mac = ltSECTIONHEADING;
  42.     if (!addToContents)
  43.       mac = ltSECTIONHEADINGSTAR;
  44.     OnMacro(mac, 0, TRUE);
  45.     OnMacro(mac, 0, FALSE);
  46.   }
  47.   else
  48.   {
  49.     int mac = ltCHAPTERHEADING;
  50.     if (!addToContents)
  51.       mac = ltCHAPTERHEADINGSTAR;
  52.     OnMacro(mac, 0, TRUE);
  53.     OnMacro(mac, 0, FALSE);
  54.   }
  55. }
  56.  
  57. // Look for \label macro, use this ref name if found or
  58. // make up a topic name otherwise.
  59. static long topicCounter = 0;
  60.  
  61. void ResetTopicCounter(void)
  62. {
  63.   topicCounter = 0;
  64. }
  65.  
  66. char *FindTopicName(TexChunk *chunk)
  67. {
  68.   char *topicName = NULL;
  69.   static char topicBuf[100];
  70.  
  71.   if (chunk && (chunk->type == CHUNK_TYPE_MACRO) &&
  72.       (chunk->macroId == ltLABEL))
  73.   {
  74.     wxNode *node = chunk->children.First();
  75.     if (node)
  76.     {
  77.       TexChunk *child = (TexChunk *)node->Data();
  78.       if (child->type == CHUNK_TYPE_ARG)
  79.       {
  80.         wxNode *snode = child->children.First();
  81.         if (snode)
  82.         {
  83.           TexChunk *schunk = (TexChunk *)snode->Data();
  84.           if (schunk->type == CHUNK_TYPE_STRING)
  85.             topicName = schunk->value;
  86.         }
  87.       }
  88.     }
  89.   }
  90.   if (topicName)
  91.     return topicName;
  92.   else
  93.   {
  94.     sprintf(topicBuf, "topic%ld", topicCounter);
  95.     topicCounter ++;
  96.     return topicBuf;
  97.   }
  98. }
  99.  
  100. /*
  101.  * Simulate argument data, so we can 'drive' clients which implement
  102.  * certain basic formatting behaviour.
  103.  * Snag is that some save a TexChunk, so don't use yet...
  104.  *
  105.  */
  106.  
  107. void StartSimulateArgument(char *data)
  108. {
  109.   strcpy(currentArgData, data);
  110.   haveArgData = TRUE;
  111. }
  112.  
  113. void EndSimulateArgument(void)
  114. {
  115.   haveArgData = FALSE;
  116. }
  117.  
  118. /*
  119.  * Parse and convert unit arguments to points
  120.  *
  121.  */
  122.  
  123. int ParseUnitArgument(char *unitArg)
  124. {
  125.   float conversionFactor = 1.0;
  126.   float unitValue = 0.0;
  127.   int len = strlen(unitArg);
  128.   // Get rid of any accidentally embedded commands
  129.   for (int i = 0; i < len; i++)
  130.     if (unitArg[i] == '\\')
  131.       unitArg[i] = 0;
  132.   len = strlen(unitArg);
  133.       
  134.   if (unitArg && (len > 0) && (isdigit(unitArg[0]) || unitArg[0] == '-'))
  135.   {
  136.     sscanf(unitArg, "%f", &unitValue);
  137.     if (len > 1)
  138.     {
  139.       char units[3]; 
  140.       units[0] = unitArg[len-2];
  141.       units[1] = unitArg[len-1];
  142.       units[2] = 0;
  143.       if (strcmp(units, "in") == 0)
  144.         conversionFactor = 72.0;
  145.       else if (strcmp(units, "cm") == 0)
  146.         conversionFactor = 72.0/2.51;
  147.       else if (strcmp(units, "mm") == 0)
  148.         conversionFactor = 72.0/25.1;
  149.       else if (strcmp(units, "pt") == 0)
  150.         conversionFactor = 1;
  151.     }
  152.     return (int)(unitValue*conversionFactor);
  153.   }
  154.   else return 0;
  155. }
  156.  
  157. /*
  158.  * Strip off any extension (dot something) from end of file,
  159.  * IF one exists. Inserts zero into buffer.
  160.  *
  161.  */
  162.  
  163. void StripExtension(char *buffer)
  164. {
  165.   int len = strlen(buffer);
  166.   int i = len-1;
  167.   while (i > 0)
  168.   {
  169.     if (buffer[i] == '.')
  170.     {
  171.       buffer[i] = 0;
  172.       break;
  173.     }
  174.     i --;
  175.   }
  176. }
  177.  
  178. /*
  179.  * Latex font setting
  180.  *
  181.  */
  182.  
  183. void SetFontSizes(int pointSize)
  184. {
  185.   switch (pointSize)
  186.   {
  187.     case 12:
  188.     {
  189.       normalFont = 12;
  190.       smallFont = 10;
  191.       tinyFont = 8;
  192.       largeFont1 = 14;
  193.       LargeFont2 = 16;
  194.       LARGEFont3 = 20;
  195.       hugeFont1 = 24;
  196.       HugeFont2 = 28;
  197.       HUGEFont3 = 32;
  198.       break;
  199.     }
  200.     case 11:
  201.     {
  202.       normalFont = 11;
  203.       smallFont = 9;
  204.       tinyFont = 7;
  205.       largeFont1 = 13;
  206.       LargeFont2 = 16;
  207.       LARGEFont3 = 19;
  208.       hugeFont1 = 22;
  209.       HugeFont2 = 26;
  210.       HUGEFont3 = 30;
  211.       break;
  212.     }
  213.     case 10:
  214.     {
  215.       normalFont = 10;
  216.       smallFont = 8;
  217.       tinyFont = 6;
  218.       largeFont1 = 12;
  219.       LargeFont2 = 14;
  220.       LARGEFont3 = 18;
  221.       hugeFont1 = 20;
  222.       HugeFont2 = 24;
  223.       HUGEFont3 = 28;
  224.       break;
  225.     }
  226.   }
  227. }
  228.  
  229.  
  230. /*
  231.  * Latex references
  232.  *
  233.  */
  234.  
  235. void AddTexRef(char *name, char *file, char *sectionName,
  236.                int chapter, int section, int subsection, int subsubsection)
  237. {
  238.   TexRef *texRef = (TexRef *)TexReferences.Get(name);
  239.   if (texRef) TexReferences.Delete(name);
  240.   
  241.   char buf[100];
  242.   buf[0] = 0;
  243.   if (sectionName)
  244.   {
  245.     strcat(buf, sectionName);
  246.     strcat(buf, " ");
  247.   }
  248.  
  249.   if (chapter)
  250.   {
  251.     char buf2[10];
  252.     sprintf(buf2, "%d", chapter);
  253.     strcat(buf, buf2);
  254.   }
  255.   if (section)
  256.   {
  257.     char buf2[10];
  258.     if (chapter)
  259.       strcat(buf, ".");
  260.  
  261.     sprintf(buf2, "%d", section);
  262.     strcat(buf, buf2);
  263.   }
  264.   if (subsection)
  265.   {
  266.     char buf2[10];
  267.     strcat(buf, ".");
  268.     sprintf(buf2, "%d", subsection);
  269.     strcat(buf, buf2);
  270.   }
  271.   if (subsubsection)
  272.   {
  273.     char buf2[10];
  274.     strcat(buf, ".");
  275.     sprintf(buf2, "%d", subsubsection);
  276.     strcat(buf, buf2);
  277.   }
  278.   TexReferences.Put(name, new TexRef(name, file, (strlen(buf) > 0) ? buf : NULL));
  279. }
  280.  
  281. void WriteTexReferences(char *filename)
  282. {
  283.   ofstream ostr(filename);
  284.   if (ostr.bad()) return;
  285.   char buf[200];
  286.   
  287.   TexReferences.BeginFind();
  288.   wxNode *node = TexReferences.Next();
  289.   while (node)
  290.   {
  291.     Tex2RTFYield();
  292.     TexRef *ref = (TexRef *)node->Data();
  293.     ostr << ref->refLabel << " " << (ref->refFile ? ref->refFile : "??") << " ";
  294.     ostr << (ref->sectionNumber ? ref->sectionNumber : "??") << "\n";
  295.     if (!ref->sectionNumber || (strcmp(ref->sectionNumber, "??") == 0))
  296.     {
  297.       sprintf(buf, "Warning: reference %s not resolved.", ref->refLabel);
  298.       OnInform(buf);
  299.     }
  300.     node = TexReferences.Next();
  301.   }
  302. }
  303.  
  304. void ReadTexReferences(char *filename)
  305. {
  306.   ifstream istr(filename, ios::nocreate | ios::in);
  307.   if (istr.bad()) return;
  308.  
  309.   char label[100];
  310.   char file[400];
  311.   char section[100];
  312.  
  313.   while (!istr.eof())
  314.   {
  315.     istr >> label;
  316.     if (!istr.eof())
  317.     {
  318.       istr >> file;
  319.       char ch;
  320.       istr.get(ch); // Read past space
  321.       istr.get(ch);
  322.       int i = 0;
  323.       while (ch != '\n' && !istr.eof())
  324.       {
  325.         section[i] = ch;
  326.         i ++;
  327.         istr.get(ch);
  328.       }
  329.       section[i] = 0;
  330.       TexReferences.Put(label, new TexRef(label, file, section));
  331.     }
  332.   }
  333. }
  334.  
  335.  
  336. /*
  337.  * Bibliography-handling code
  338.  *
  339.  */
  340.  
  341. void BibEatWhiteSpace(istream& str)
  342. {
  343.   char ch = str.peek();
  344.   
  345.   while (!str.eof() && (ch == ' ' || ch == '\t' || ch == 13 || ch == 10 || ch == EOF))
  346.   {
  347.     if (ch == 10)
  348.       BibLine ++;
  349.     str.get(ch);
  350.     if ((ch == EOF) || str.eof()) return;
  351.     ch = str.peek();
  352.   }
  353.  
  354.   // Ignore end-of-line comments
  355.   if (ch == '%' || ch == ';' || ch == '#')
  356.   {
  357.     str.get(ch);
  358.     ch = str.peek();
  359.     while (ch != 10 && ch != 13 && ch != EOF)
  360.     {
  361.       str.get(ch);
  362.       ch = str.peek();
  363.     }
  364.     BibEatWhiteSpace(str);
  365.   }
  366. }
  367.  
  368. // Read word up to { or , or space
  369. void BibReadWord(istream& istr, char *buffer)
  370. {
  371.   int i = 0;
  372.   buffer[i] = 0;
  373.   char ch = istr.peek();
  374.   while (!istr.eof() && ch != ' ' && ch != '{' && ch != '(' && ch != 13 && ch != 10 && ch != '\t' &&
  375.          ch != ',' && ch != '=')
  376.   {
  377.     istr.get(ch);
  378.     buffer[i] = ch;
  379.     i ++;
  380.     ch = istr.peek();
  381.   }
  382.   buffer[i] = 0;
  383. }
  384.  
  385. // Read string (double-quoted or not) to end quote or EOL
  386. void BibReadToEOL(istream& istr, char *buffer)
  387. {
  388.   int i = 0;
  389.   buffer[i] = 0;
  390.   char ch = istr.peek();
  391.   Bool inQuotes = FALSE;
  392.   if (ch == '"')
  393.   {
  394.     istr.get(ch);
  395.     ch = istr.peek();
  396.     inQuotes = TRUE;
  397.   }
  398.   // If in quotes, read white space too. If not,
  399.   // stop at white space or comment.
  400.   while (!istr.eof() && ch != 13 && ch != 10 && ch != '"' &&
  401.          (inQuotes || ((ch != ' ') && (ch != 9) &&
  402.                         (ch != ';') && (ch != '%') && (ch != '#'))))
  403.   {
  404.     istr.get(ch);
  405.     buffer[i] = ch;
  406.     i ++;
  407.     ch = istr.peek();
  408.   }
  409.   if (ch == '"')
  410.     istr.get(ch);
  411.   buffer[i] = 0;
  412. }
  413.  
  414. // Read }-terminated value, taking nested braces into account.
  415. void BibReadValue(istream& istr, char *buffer, Bool ignoreBraces = TRUE,
  416.                   Bool quotesMayTerminate = TRUE)
  417. {
  418.   int braceCount = 1;
  419.   int i = 0;
  420.   buffer[i] = 0;
  421.   char ch = istr.peek();
  422.   Bool stopping = FALSE;
  423.   while (!istr.eof() && !stopping)
  424.   {
  425. //    i ++;
  426.     if (i >= 2000)
  427.     {
  428.       char buf[100];
  429.       sprintf(buf, "Sorry, value > 2000 chars in bib file at line %ld, terminating.", BibLine);
  430.       wxFatalError(buf, "Tex2RTF Fatal Error");
  431.     }
  432.     istr.get(ch);
  433.     
  434.     if (ch == '{')
  435.       braceCount ++;
  436.  
  437.     if (ch == '}')
  438.     {
  439.       braceCount --;
  440.       if (braceCount == 0)
  441.       {
  442.         stopping = TRUE;
  443.         break;
  444.       }
  445.     }
  446.     else if (quotesMayTerminate && ch == '"')
  447.     {
  448.       stopping = TRUE;
  449.       break;
  450.     }
  451.     if (!stopping)
  452.     {
  453.       if (!ignoreBraces || (ch != '{' && ch != '}'))
  454.       {
  455.         buffer[i] = ch;
  456.         i ++;
  457.       }
  458.     }
  459.     if (ch == 10)
  460.       BibLine ++;
  461.   }
  462.   buffer[i] = 0;
  463. }
  464.  
  465. Bool ReadBib(char *filename)
  466. {
  467.   char buf[300];
  468.   ifstream istr(filename, ios::nocreate | ios::in);
  469.   if (istr.bad()) return FALSE;
  470.  
  471.   BibLine = 1;
  472.  
  473.   OnInform("Reading .bib file...");
  474.  
  475.   char ch;
  476.   char fieldValue[2000];
  477.   char recordType[100];
  478.   char recordKey[100];
  479.   char recordField[100];
  480.   while (!istr.eof())
  481.   {
  482.     Tex2RTFYield();
  483.  
  484.     BibEatWhiteSpace(istr);
  485.     istr.get(ch);
  486.     if (ch != '@')
  487.     {
  488.       sprintf(buf, "Expected @: malformed bib file at line %ld (%s)", BibLine, filename);
  489.       OnError(buf);
  490.       return FALSE;
  491.     }
  492.     BibReadWord(istr, recordType);
  493.     BibEatWhiteSpace(istr);
  494.     istr.get(ch);
  495.     if (ch != '{' && ch != '(')
  496.     {
  497.       sprintf(buf, "Expected { or ( after record type: malformed .bib file at line %ld (%s)", BibLine, filename);
  498.       OnError(buf);
  499.       return FALSE;
  500.     }
  501.     BibEatWhiteSpace(istr);
  502.     if (StringMatch(recordType, "string", FALSE, TRUE))
  503.     {
  504.       BibReadWord(istr, recordType);
  505.       BibEatWhiteSpace(istr);
  506.       istr.get(ch);
  507.       if (ch != '=')
  508.       {
  509.         sprintf(buf, "Expected = after string key: malformed .bib file at line %ld (%s)", BibLine, filename);
  510.         OnError(buf);
  511.         return FALSE;
  512.       }
  513.       BibEatWhiteSpace(istr);
  514.       istr.get(ch);
  515.       if (ch != '"' && ch != '{')
  516.       {
  517.         sprintf(buf, "Expected = after string key: malformed .bib file at line %ld (%s)", BibLine, filename);
  518.         OnError(buf);
  519.         return FALSE;
  520.       }
  521.       BibReadValue(istr, fieldValue);
  522.  
  523.       // Now put in hash table if necesary
  524.       if (!BibStringTable.Get(recordType))
  525.         BibStringTable.Put(recordType, (wxObject *)copystring(fieldValue));
  526.  
  527.       // Read closing ) or }
  528.       BibEatWhiteSpace(istr);
  529.       istr.get(ch);
  530.       BibEatWhiteSpace(istr);
  531.     }
  532.     else
  533.     {
  534.       BibReadWord(istr, recordKey);
  535.  
  536.       BibEntry *bibEntry = new BibEntry;
  537.       bibEntry->key = copystring(recordKey);
  538.       bibEntry->type = copystring(recordType);
  539.  
  540.       Bool moreRecords = TRUE;
  541.       while (moreRecords && !istr.eof())
  542.       {
  543.         BibEatWhiteSpace(istr);
  544.         istr.get(ch);
  545.         if (ch == '}' || ch == ')')
  546.         {
  547.           moreRecords = FALSE;
  548.         }
  549.         else if (ch == ',')
  550.         {
  551.           BibEatWhiteSpace(istr);
  552.           BibReadWord(istr, recordField);
  553.           BibEatWhiteSpace(istr);
  554.           istr.get(ch);
  555.           if (ch != '=')
  556.           {
  557.             sprintf(buf, "Expected = after field type: malformed .bib file at line %ld (%s)", BibLine, filename);
  558.             OnError(buf);
  559.             return FALSE;
  560.           }
  561.           BibEatWhiteSpace(istr);
  562.           istr.get(ch);
  563.           if (ch != '{' && ch != '"')
  564.           {
  565.             fieldValue[0] = ch;
  566.             BibReadWord(istr, fieldValue+1);
  567.  
  568.             // If in the table of strings, replace with string from table.
  569.             char *s = (char *)BibStringTable.Get(fieldValue);
  570.             if (s)
  571.             {
  572.               strcpy(fieldValue, s);
  573.             }
  574.           }
  575.           else
  576.             BibReadValue(istr, fieldValue, TRUE, (ch == '"' ? TRUE : FALSE));
  577.  
  578.           // Now we can add a field
  579.           if (StringMatch(recordField, "author", FALSE, TRUE))
  580.             bibEntry->author = copystring(fieldValue);
  581.           else if (StringMatch(recordField, "key", FALSE, TRUE))
  582.             {}
  583.           else if (StringMatch(recordField, "annotate", FALSE, TRUE))
  584.             {}
  585.           else if (StringMatch(recordField, "abstract", FALSE, TRUE))
  586.             {}
  587.           else if (StringMatch(recordField, "edition", FALSE, TRUE))
  588.             {}
  589.           else if (StringMatch(recordField, "howpublished", FALSE, TRUE))
  590.             {}
  591.           else if (StringMatch(recordField, "note", FALSE, TRUE) || StringMatch(recordField, "notes", FALSE, TRUE))
  592.             {}
  593.           else if (StringMatch(recordField, "series", FALSE, TRUE))
  594.             {}
  595.           else if (StringMatch(recordField, "type", FALSE, TRUE))
  596.             {}
  597.           else if (StringMatch(recordField, "keywords", FALSE, TRUE))
  598.             {}
  599.           else if (StringMatch(recordField, "editor", FALSE, TRUE) || StringMatch(recordField, "editors", FALSE, TRUE))
  600.             bibEntry->editor= copystring(fieldValue);
  601.           else if (StringMatch(recordField, "title", FALSE, TRUE))
  602.             bibEntry->title= copystring(fieldValue);
  603.           else if (StringMatch(recordField, "booktitle", FALSE, TRUE))
  604.             bibEntry->booktitle= copystring(fieldValue);
  605.           else if (StringMatch(recordField, "journal", FALSE, TRUE))
  606.             bibEntry->journal= copystring(fieldValue);
  607.           else if (StringMatch(recordField, "volume", FALSE, TRUE))
  608.             bibEntry->volume= copystring(fieldValue);
  609.           else if (StringMatch(recordField, "number", FALSE, TRUE))
  610.             bibEntry->number= copystring(fieldValue);
  611.           else if (StringMatch(recordField, "year", FALSE, TRUE))
  612.             bibEntry->year= copystring(fieldValue);
  613.           else if (StringMatch(recordField, "month", FALSE, TRUE))
  614.             bibEntry->month= copystring(fieldValue);
  615.           else if (StringMatch(recordField, "pages", FALSE, TRUE))
  616.             bibEntry->pages= copystring(fieldValue);
  617.           else if (StringMatch(recordField, "publisher", FALSE, TRUE))
  618.             bibEntry->publisher= copystring(fieldValue);
  619.           else if (StringMatch(recordField, "address", FALSE, TRUE))
  620.             bibEntry->address= copystring(fieldValue);
  621.           else if (StringMatch(recordField, "institution", FALSE, TRUE) || StringMatch(recordField, "school", FALSE, TRUE))
  622.             bibEntry->institution= copystring(fieldValue);
  623.           else if (StringMatch(recordField, "organization", FALSE, TRUE) || StringMatch(recordField, "organisation", FALSE, TRUE))
  624.             bibEntry->organization= copystring(fieldValue);
  625.           else if (StringMatch(recordField, "comment", FALSE, TRUE) || StringMatch(recordField, "comments", FALSE, TRUE))
  626.             bibEntry->comment= copystring(fieldValue);
  627.           else if (StringMatch(recordField, "annote", FALSE, TRUE))
  628.             bibEntry->comment= copystring(fieldValue);
  629.           else if (StringMatch(recordField, "chapter", FALSE, TRUE))
  630.             bibEntry->chapter= copystring(fieldValue);
  631.           else
  632.           {
  633.             sprintf(buf, "Unrecognised bib field type %s at line %ld (%s)", recordField, BibLine, filename);
  634.             OnError(buf);
  635.           }
  636.         }
  637.       }
  638.       BibList.Append(recordKey, bibEntry);
  639.       BibEatWhiteSpace(istr);
  640.     }
  641.   }
  642.   return TRUE;
  643. }
  644.  
  645. void OutputBibItem(TexRef *ref, BibEntry *bib)
  646. {
  647.   Tex2RTFYield();
  648.  
  649.   OnMacro(ltNUMBEREDBIBITEM, 2, TRUE);
  650.   OnArgument(ltNUMBEREDBIBITEM, 1, TRUE);
  651.   TexOutput(ref->sectionNumber);
  652.   OnArgument(ltNUMBEREDBIBITEM, 1, FALSE);
  653.   OnArgument(ltNUMBEREDBIBITEM, 2, TRUE);
  654.  
  655.   TexOutput(" ");
  656.   OnMacro(ltBF, 1, TRUE);
  657.   OnArgument(ltBF, 1, TRUE);
  658.   if (bib->author)
  659.     TexOutput(bib->author);
  660.   OnArgument(ltBF, 1, FALSE);
  661.   OnMacro(ltBF, 1, FALSE);
  662.   if (bib->author && (strlen(bib->author) > 0) && (bib->author[strlen(bib->author) - 1] != '.'))
  663.     TexOutput(". ");
  664.   else
  665.     TexOutput(" ");
  666.  
  667.   if (bib->year)
  668.   {
  669.     TexOutput(bib->year);
  670.   }
  671.   if (bib->month)
  672.   {
  673.     TexOutput(" (");
  674.     TexOutput(bib->month);
  675.     TexOutput(")");
  676.   }
  677.   if (bib->year || bib->month)
  678.     TexOutput(". ");
  679.  
  680.   if (StringMatch(bib->type, "article", FALSE, TRUE))
  681.   {
  682.     if (bib->title)
  683.     {
  684.       TexOutput(bib->title);
  685.       TexOutput(". ");
  686.     }
  687.     if (bib->journal)
  688.     {
  689.       OnMacro(ltIT, 1, TRUE);
  690.       OnArgument(ltIT, 1, TRUE);
  691.       TexOutput(bib->journal);
  692.       OnArgument(ltIT, 1, FALSE);
  693.       OnMacro(ltIT, 1, FALSE);
  694.     }
  695.     if (bib->volume)
  696.     {
  697.       TexOutput(", ");
  698.       OnMacro(ltBF, 1, TRUE);
  699.       OnArgument(ltBF, 1, TRUE);
  700.       TexOutput(bib->volume);
  701.       OnArgument(ltBF, 1, FALSE);
  702.       OnMacro(ltBF, 1, FALSE);
  703.     }
  704.     if (bib->number)
  705.     {
  706.       TexOutput("(");
  707.       TexOutput(bib->number);
  708.       TexOutput(")");
  709.     }
  710.     if (bib->pages)
  711.     {
  712.       TexOutput(", pages ");
  713.       TexOutput(bib->pages);
  714.     }
  715.     TexOutput(".");
  716.   }
  717.   else if (StringMatch(bib->type, "book", FALSE, TRUE) ||
  718.            StringMatch(bib->type, "unpublished", FALSE, TRUE) ||
  719.            StringMatch(bib->type, "manual", FALSE, TRUE) ||
  720.            StringMatch(bib->type, "phdthesis", FALSE, TRUE) ||
  721.            StringMatch(bib->type, "mastersthesis", FALSE, TRUE) ||
  722.            StringMatch(bib->type, "misc", FALSE, TRUE) ||
  723.            StringMatch(bib->type, "techreport", FALSE, TRUE) ||
  724.            StringMatch(bib->type, "booklet", FALSE, TRUE))
  725.   {
  726.     if (bib->title || bib->booktitle)
  727.     {
  728.       OnMacro(ltIT, 1, TRUE);
  729.       OnArgument(ltIT, 1, TRUE);
  730.       TexOutput(bib->title ? bib->title : bib->booktitle);
  731.       TexOutput(". ");
  732.       OnArgument(ltIT, 1, FALSE);
  733.       OnMacro(ltIT, 1, FALSE);
  734.     }
  735.     if (StringMatch(bib->type, "phdthesis", FALSE, TRUE))
  736.       TexOutput("PhD thesis. ");
  737.     if (StringMatch(bib->type, "techreport", FALSE, TRUE))
  738.       TexOutput("Technical report. ");
  739.     if (bib->editor)
  740.     {
  741.       TexOutput("Ed. ");
  742.       TexOutput(bib->editor);
  743.       TexOutput(". ");
  744.     }
  745.     if (bib->institution)
  746.     {
  747.       TexOutput(bib->institution);
  748.       TexOutput(". ");
  749.     }
  750.     if (bib->organization)
  751.     {
  752.       TexOutput(bib->organization);
  753.       TexOutput(". ");
  754.     }
  755.     if (bib->publisher)
  756.     {
  757.       TexOutput(bib->publisher);
  758.       TexOutput(". ");
  759.     }
  760.     if (bib->address)
  761.     {
  762.       TexOutput(bib->address);
  763.       TexOutput(". ");
  764.     }
  765.   }
  766.   else if (StringMatch(bib->type, "inbook", FALSE, TRUE) ||
  767.            StringMatch(bib->type, "inproceedings", FALSE, TRUE) ||
  768.            StringMatch(bib->type, "incollection", FALSE, TRUE) ||
  769.            StringMatch(bib->type, "conference", FALSE, TRUE))
  770.   {
  771.     if (bib->title)
  772.     {
  773.       TexOutput(bib->title);
  774.     }
  775.     if (bib->booktitle)
  776.     {
  777.       TexOutput(", from ");
  778.       OnMacro(ltIT, 1, TRUE);
  779.       OnArgument(ltIT, 1, TRUE);
  780.       TexOutput(bib->booktitle);
  781.       TexOutput(".");
  782.       OnArgument(ltIT, 1, FALSE);
  783.       OnMacro(ltIT, 1, FALSE);
  784.     }
  785.     if (bib->editor)
  786.     {
  787.       TexOutput(", ed. ");
  788.       TexOutput(bib->editor);
  789.     }
  790.     if (bib->publisher)
  791.     {
  792.       TexOutput(" ");
  793.       TexOutput(bib->publisher);
  794.     }
  795.     if (bib->address)
  796.     {
  797.       if (bib->publisher) TexOutput(", ");
  798.       else TexOutput(" ");
  799.       TexOutput(bib->address);
  800.     }
  801.     if (bib->publisher || bib->address)
  802.       TexOutput(".");
  803.  
  804.     if (bib->volume)
  805.     {
  806.       TexOutput(" ");
  807.       OnMacro(ltBF, 1, TRUE);
  808.       OnArgument(ltBF, 1, TRUE);
  809.       TexOutput(bib->volume);
  810.       OnArgument(ltBF, 1, FALSE);
  811.       OnMacro(ltBF, 1, FALSE);
  812.     }
  813.     if (bib->number)
  814.     {
  815.       if (bib->volume)
  816.       {
  817.         TexOutput("(");
  818.         TexOutput(bib->number);
  819.         TexOutput(").");
  820.       }
  821.       else
  822.       {
  823.         TexOutput(" Number ");
  824.         TexOutput(bib->number);
  825.         TexOutput(".");
  826.       }
  827.     }
  828.     if (bib->chapter)
  829.     {
  830.       TexOutput(" Chap. "); TexOutput(bib->chapter);
  831.     }
  832.     if (bib->pages)
  833.     {
  834.       if (bib->chapter) TexOutput(", pages ");
  835.       else TexOutput(" Pages ");
  836.       TexOutput(bib->pages);
  837.       TexOutput(".");
  838.     }
  839.   }
  840.   OnArgument(ltNUMBEREDBIBITEM, 2, FALSE);
  841.   OnMacro(ltNUMBEREDBIBITEM, 2, FALSE);
  842. }
  843.  
  844. void OutputBib(void)
  845. {
  846.   // Write the heading
  847.   FakeCurrentSection(ReferencesNameString);
  848.  
  849.   OnMacro(ltPAR, 0, TRUE);
  850.   OnMacro(ltPAR, 0, FALSE);
  851.  
  852.   if ((convertMode == TEX_RTF) && !winHelp)
  853.   {
  854.     OnMacro(ltPAR, 0, TRUE);
  855.     OnMacro(ltPAR, 0, FALSE);
  856.   }
  857.  
  858.   wxNode *node = CitationList.First();
  859.   while (node)
  860.   {
  861.     char *citeKey = (char *)node->Data();
  862. //    wxNode *texNode = TexReferences.Find(citeKey);
  863.     TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
  864.     wxNode *bibNode = BibList.Find(citeKey);
  865.     if (bibNode && ref)
  866.     {
  867.       BibEntry *entry = (BibEntry *)bibNode->Data();
  868.       OutputBibItem(ref, entry);
  869.     }
  870.     node = node->Next();
  871.   }
  872. }
  873.  
  874. static int citeCount = 1;
  875.  
  876. void ResolveBibReferences(void)
  877. {
  878.   if (CitationList.Number() > 0)
  879.     OnInform("Resolving bibliographic references...");
  880.  
  881.   citeCount = 1;
  882.   char buf[200];
  883.   wxNode *node = CitationList.First();
  884.   while (node)
  885.   {
  886.     Tex2RTFYield();
  887.     char *citeKey = (char *)node->Data();
  888. //    wxNode *texNode = TexReferences.Find(citeKey);
  889.     TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
  890.     wxNode *bibNode = BibList.Find(citeKey);
  891.     if (bibNode && ref)
  892.     {
  893.       // Unused Variable
  894.       //BibEntry *entry = (BibEntry *)bibNode->Data();
  895.       if (ref->sectionNumber) delete[] ref->sectionNumber;
  896.       sprintf(buf, "[%d]", citeCount);
  897.       ref->sectionNumber = copystring(buf);
  898.       citeCount ++;
  899.     }
  900.     else
  901.     {
  902.       sprintf(buf, "Warning: bib ref %s not resolved.", citeKey);
  903.       OnInform(buf);
  904.     }
  905.     node = node->Next();
  906.   }
  907. }
  908.  
  909. // Remember we need to resolve this citation
  910. void AddCitation(char *citeKey)
  911. {
  912.   if (!CitationList.Member(citeKey))
  913.     CitationList.Add(citeKey);
  914.  
  915.   if (!TexReferences.Get(citeKey))
  916.   {
  917.     TexReferences.Put(citeKey, new TexRef(citeKey, "??", NULL));
  918.   }
  919. }
  920.  
  921. TexRef *FindReference(char *key)
  922. {
  923.   return (TexRef *)TexReferences.Get(key);
  924. }
  925.  
  926. /*
  927.  * Custom macro stuff
  928.  *
  929.  */
  930.  
  931. Bool StringToBool(char *val)
  932. {
  933.   if (strcmp(val, "yes") == 0 || strcmp(val, "YES") == 0 ||
  934.       strcmp(val, "on") == 0 || strcmp(val, "ON") == 0 ||
  935.       strcmp(val, "true") == 0 || strcmp(val, "TRUE") == 0 ||
  936.       strcmp(val, "ok") == 0 || strcmp(val, "OK") == 0 ||
  937.       strcmp(val, "1") == 0)
  938.     return TRUE;
  939.   else
  940.     return FALSE;
  941. }
  942.  
  943. // Define a variable value from the .ini file
  944. char *RegisterSetting(char *settingName, char *settingValue, Bool interactive)
  945. {
  946.   static char errorCode[100];
  947.   strcpy(errorCode, "OK");
  948.   if (StringMatch(settingName, "chapterName", FALSE, TRUE))
  949.   {
  950.     delete[] ChapterNameString;
  951.     ChapterNameString = copystring(settingValue);
  952.   }
  953.   else if (StringMatch(settingName, "sectionName", FALSE, TRUE))
  954.   {
  955.     delete[] SectionNameString;
  956.     SectionNameString = copystring(settingValue);
  957.   }
  958.   else if (StringMatch(settingName, "subsectionName", FALSE, TRUE))
  959.   {
  960.     delete[] SubsectionNameString;
  961.     SubsectionNameString = copystring(settingValue);
  962.   }
  963.   else if (StringMatch(settingName, "subsubsectionName", FALSE, TRUE))
  964.   {
  965.     delete[] SubsubsectionNameString;
  966.     SubsubsectionNameString = copystring(settingValue);
  967.   }
  968.   else if (StringMatch(settingName, "indexName", FALSE, TRUE))
  969.   {
  970.     delete[] IndexNameString;
  971.     IndexNameString = copystring(settingValue);
  972.   }
  973.   else if (StringMatch(settingName, "contentsName", FALSE, TRUE))
  974.   {
  975.     delete[] ContentsNameString;
  976.     ContentsNameString = copystring(settingValue);
  977.   }
  978.   else if (StringMatch(settingName, "glossaryName", FALSE, TRUE))
  979.   {
  980.     delete[] GlossaryNameString;
  981.     GlossaryNameString = copystring(settingValue);
  982.   }
  983.   else if (StringMatch(settingName, "referencesName", FALSE, TRUE))
  984.   {
  985.     delete[] ReferencesNameString;
  986.     ReferencesNameString = copystring(settingValue);
  987.   }
  988.   else if (StringMatch(settingName, "tablesName", FALSE, TRUE))
  989.   {
  990.     delete[] TablesNameString;
  991.     TablesNameString = copystring(settingValue);
  992.   }
  993.   else if (StringMatch(settingName, "figuresName", FALSE, TRUE))
  994.   {
  995.     delete[] FiguresNameString;
  996.     FiguresNameString = copystring(settingValue);
  997.   }
  998.   else if (StringMatch(settingName, "tableName", FALSE, TRUE))
  999.   {
  1000.     delete[] TableNameString;
  1001.     TableNameString = copystring(settingValue);
  1002.   }
  1003.   else if (StringMatch(settingName, "figureName", FALSE, TRUE))
  1004.   {
  1005.     delete[] FigureNameString;
  1006.     FigureNameString = copystring(settingValue);
  1007.   }
  1008.   else if (StringMatch(settingName, "chapterFontSize", FALSE, TRUE))
  1009.     StringToInt(settingValue, &chapterFont);
  1010.   else if (StringMatch(settingName, "sectionFontSize", FALSE, TRUE))
  1011.     StringToInt(settingValue, §ionFont);
  1012.   else if (StringMatch(settingName, "subsectionFontSize", FALSE, TRUE))
  1013.     StringToInt(settingValue, &subsectionFont);
  1014.   else if (StringMatch(settingName, "titleFontSize", FALSE, TRUE))
  1015.     StringToInt(settingValue, &titleFont);
  1016.   else if (StringMatch(settingName, "authorFontSize", FALSE, TRUE))
  1017.     StringToInt(settingValue, &authorFont);
  1018.   else if (StringMatch(settingName, "ignoreInput", FALSE, TRUE))
  1019.     IgnorableInputFiles.Add(FileNameFromPath(settingValue));
  1020.   else if (StringMatch(settingName, "mirrorMargins", FALSE, TRUE))
  1021.     mirrorMargins = StringToBool(settingValue);
  1022.   else if (StringMatch(settingName, "runTwice", FALSE, TRUE))
  1023.     runTwice = StringToBool(settingValue);
  1024.   else if (StringMatch(settingName, "isInteractive", FALSE, TRUE))
  1025.     isInteractive = StringToBool(settingValue);
  1026.   else if (StringMatch(settingName, "headerRule", FALSE, TRUE))
  1027.     headerRule = StringToBool(settingValue);
  1028.   else if (StringMatch(settingName, "footerRule", FALSE, TRUE))
  1029.     footerRule = StringToBool(settingValue);
  1030.   else if (StringMatch(settingName, "listLabelIndent", FALSE, TRUE))
  1031.     StringToInt(settingValue, &labelIndentTab);
  1032.   else if (StringMatch(settingName, "listItemIndent", FALSE, TRUE))
  1033.     StringToInt(settingValue, &itemIndentTab);
  1034.   else if (StringMatch(settingName, "useUpButton", FALSE, TRUE))
  1035.     useUpButton = StringToBool(settingValue);
  1036.   else if (StringMatch(settingName, "useHeadingStyles", FALSE, TRUE))
  1037.     useHeadingStyles = StringToBool(settingValue);
  1038.   else if (StringMatch(settingName, "useWord", FALSE, TRUE))
  1039.     useWord = StringToBool(settingValue);
  1040.   else if (StringMatch(settingName, "generateHPJ", FALSE, TRUE))
  1041.     generateHPJ = StringToBool(settingValue);
  1042.   else if (StringMatch(settingName, "winHelpTitle", FALSE, TRUE))
  1043.   {
  1044.     if (winHelpTitle)
  1045.       delete[] winHelpTitle;
  1046.     winHelpTitle = copystring(settingValue);
  1047.   }
  1048.   else if (StringMatch(settingName, "indexSubsections", FALSE, TRUE))
  1049.     indexSubsections = StringToBool(settingValue);
  1050.   else if (StringMatch(settingName, "compatibility", FALSE, TRUE))
  1051.     compatibilityMode = StringToBool(settingValue);
  1052.   else if (StringMatch(settingName, "defaultColumnWidth", FALSE, TRUE))
  1053.   {
  1054.     StringToInt(settingValue, &defaultTableColumnWidth);
  1055.     defaultTableColumnWidth = 20*defaultTableColumnWidth;
  1056.   }
  1057.   else if (StringMatch(settingName, "bitmapMethod", FALSE, TRUE))
  1058.   {
  1059.     if ((strcmp(settingValue, "includepicture") != 0) && (strcmp(settingValue, "hex") != 0) &&
  1060.         (strcmp(settingValue, "import") != 0))
  1061.     {
  1062.       if (interactive)
  1063.         OnError("Unknown bitmapMethod");
  1064.       strcpy(errorCode, "Unknown bitmapMethod");
  1065.     }
  1066.     else
  1067.     {
  1068.       delete[] bitmapMethod;
  1069.       bitmapMethod = copystring(settingValue);
  1070.     }
  1071.   }
  1072.   else if (StringMatch(settingName, "htmlBrowseButtons", FALSE, TRUE))
  1073.   {
  1074.     if (strcmp(settingValue, "none") == 0)
  1075.       htmlBrowseButtons = HTML_BUTTONS_NONE;
  1076.     else if (strcmp(settingValue, "bitmap") == 0)
  1077.       htmlBrowseButtons = HTML_BUTTONS_BITMAP;
  1078.     else if (strcmp(settingValue, "text") == 0)
  1079.       htmlBrowseButtons = HTML_BUTTONS_TEXT;
  1080.     else
  1081.     {
  1082.       if (interactive)
  1083.         OnInform("Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text.");
  1084.       strcpy(errorCode, "Initialisation file error: htmlBrowseButtons must be one of none, bitmap, or text.");
  1085.     }
  1086.   }
  1087.   else if (StringMatch(settingName, "conversionMode", FALSE, TRUE))
  1088.   {
  1089.     if (StringMatch(settingValue, "RTF", FALSE, TRUE))
  1090.     {
  1091.       winHelp = FALSE; convertMode = TEX_RTF;
  1092.     }
  1093.     else if (StringMatch(settingValue, "WinHelp", FALSE, TRUE))
  1094.     {
  1095.       winHelp = TRUE; convertMode = TEX_RTF;
  1096.     }
  1097.     else if (StringMatch(settingValue, "XLP", FALSE, TRUE) ||
  1098.              StringMatch(settingValue, "wxHelp", FALSE, TRUE))
  1099.     {
  1100.       convertMode = TEX_XLP;
  1101.     }
  1102.     else if (StringMatch(settingValue, "HTML", FALSE, TRUE))
  1103.     {
  1104.       convertMode = TEX_HTML;
  1105.     }
  1106.     else
  1107.     {
  1108.       if (interactive)
  1109.         OnInform("Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML.");
  1110.       strcpy(errorCode, "Initialisation file error: conversionMode must be one of\nRTF, WinHelp, XLP (or wxHelp), HTML.");
  1111.     }
  1112.   }
  1113.   else if (StringMatch(settingName, "documentFontSize", FALSE, TRUE))
  1114.   {
  1115.     int n;
  1116.     StringToInt(settingValue, &n);
  1117.     if (n == 10 || n == 11 || n == 12)
  1118.       SetFontSizes(n);
  1119.     else
  1120.     {
  1121.       char buf[200];
  1122.       sprintf(buf, "Initialisation file error: nonstandard document font size %d.", n);
  1123.       if (interactive)
  1124.         OnInform(buf);
  1125.       strcpy(errorCode, buf);
  1126.     }
  1127.   }
  1128.   else
  1129.   {
  1130.     char buf[200];
  1131.     sprintf(buf, "Initialisation file error: unrecognised setting %s.", settingName);
  1132.     if (interactive)
  1133.       OnInform(buf);
  1134.     strcpy(errorCode, buf);
  1135.   }
  1136.   return errorCode;
  1137. }
  1138.  
  1139. Bool ReadCustomMacros(char *filename)
  1140. {
  1141.   ifstream istr(filename, ios::nocreate | ios::in);
  1142.   if (istr.bad()) return FALSE;
  1143.  
  1144.   CustomMacroList.Clear();
  1145.   char ch;
  1146.   char macroName[100];
  1147.   char macroBody[1000];
  1148.   int noArgs;
  1149.  
  1150.   while (!istr.eof())
  1151.   {
  1152.     BibEatWhiteSpace(istr);
  1153.     istr.get(ch);
  1154.     if (istr.eof())
  1155.       break;
  1156.       
  1157.     if (ch != '\\') // Not a macro definition, so must be NAME=VALUE
  1158.     {
  1159.       char settingName[100];
  1160.       settingName[0] = ch;
  1161.       BibReadWord(istr, (settingName+1));
  1162.       BibEatWhiteSpace(istr);
  1163.       istr.get(ch);
  1164.       if (ch != '=')
  1165.       {
  1166.         OnError("Expected = following name: malformed tex2rtf.ini file.");
  1167.         return FALSE;
  1168.       }
  1169.       else
  1170.       {
  1171.         char settingValue[200];
  1172.         BibEatWhiteSpace(istr);
  1173.         BibReadToEOL(istr, settingValue);
  1174.         RegisterSetting(settingName, settingValue);
  1175.       }
  1176.     }
  1177.     else
  1178.     {
  1179.       BibReadWord(istr, macroName);
  1180.       BibEatWhiteSpace(istr);
  1181.       istr.get(ch);
  1182.       if (ch != '[')
  1183.       {
  1184.         OnError("Expected [ followed by number of arguments: malformed tex2rtf.ini file.");
  1185.         return FALSE;
  1186.       }
  1187.       istr >> noArgs;
  1188.       istr.get(ch);
  1189.       if (ch != ']')
  1190.       {
  1191.         OnError("Expected ] following number of arguments: malformed tex2rtf.ini file.");
  1192.         return FALSE;
  1193.       }
  1194.       BibEatWhiteSpace(istr);
  1195.       istr.get(ch);
  1196.       if (ch != '{')
  1197.       {
  1198.         OnError("Expected { followed by macro body: malformed tex2rtf.ini file.");
  1199.         return FALSE;
  1200.       }
  1201.       CustomMacro *macro = new CustomMacro(macroName, noArgs, NULL);
  1202.       BibReadValue(istr, macroBody, FALSE, FALSE); // Don't ignore extra braces
  1203.       if (strlen(macroBody) > 0)
  1204.         macro->macroBody = copystring(macroBody);
  1205.     
  1206.       BibEatWhiteSpace(istr);
  1207.       CustomMacroList.Append(macroName, macro);
  1208.       AddMacroDef(ltCUSTOM_MACRO, macroName, noArgs);
  1209.     }
  1210.   }
  1211.   char mbuf[200];
  1212.   sprintf(mbuf, "Read initialization file %s.", filename);
  1213.   OnInform(mbuf);
  1214.   return TRUE;
  1215. }
  1216.  
  1217. CustomMacro *FindCustomMacro(char *name)
  1218. {
  1219.   wxNode *node = CustomMacroList.Find(name);
  1220.   if (node)
  1221.   {
  1222.     CustomMacro *macro = (CustomMacro *)node->Data();
  1223.     return macro;
  1224.   }
  1225.   return NULL;
  1226. }
  1227.  
  1228. // Display custom macros
  1229. void ShowCustomMacros(void)
  1230. {
  1231.   wxNode *node = CustomMacroList.First();
  1232.   if (!node)
  1233.   {
  1234.     OnInform("No custom macros loaded.\n");
  1235.     return;
  1236.   }
  1237.   
  1238.   char buf[400];
  1239.   while (node)
  1240.   {
  1241.     CustomMacro *macro = (CustomMacro *)node->Data();
  1242.     sprintf(buf, "\\%s[%d]\n    {%s}", macro->macroName, macro->noArgs,
  1243.      macro->macroBody ? macro->macroBody : "");
  1244.     OnInform(buf);
  1245.     node = node->Next();
  1246.   }
  1247. }
  1248.  
  1249. // Parse a string into several comma-separated fields
  1250. char *ParseMultifieldString(char *allFields, int *pos)
  1251. {
  1252.   static char buffer[300];
  1253.   int i = 0;
  1254.   int fieldIndex = *pos;
  1255.   int len = strlen(allFields);
  1256.   int oldPos = *pos;
  1257.   Bool keepGoing = TRUE;
  1258.   while ((fieldIndex <= len) && keepGoing)
  1259.   {
  1260.     if (allFields[fieldIndex] == ' ')
  1261.     {
  1262.       // Skip
  1263.       fieldIndex ++;
  1264.     }
  1265.     else if (allFields[fieldIndex] == ',')
  1266.     {
  1267.       *pos = fieldIndex + 1;
  1268.       keepGoing = FALSE;
  1269.     }
  1270.     else if (allFields[fieldIndex] == 0)
  1271.     {
  1272.       *pos = fieldIndex + 1;
  1273.       keepGoing = FALSE;
  1274.     }
  1275.     else
  1276.     {
  1277.       buffer[i] = allFields[fieldIndex];
  1278.       fieldIndex ++;
  1279.       i++;
  1280.     }
  1281.   }
  1282.   buffer[i] = 0;
  1283.   if (oldPos == (*pos))
  1284.     *pos = len + 1;
  1285.     
  1286.   if (i == 0)
  1287.     return NULL;
  1288.   else
  1289.     return buffer;
  1290. }
  1291.  
  1292. /*
  1293.  * Colour tables
  1294.  *
  1295.  */
  1296.  
  1297. ColourTableEntry::ColourTableEntry(char *theName, unsigned int r,  unsigned int g,  unsigned int b)
  1298. {
  1299.   name = copystring(theName);
  1300.   red = r;
  1301.   green = g;
  1302.   blue = b;
  1303. }
  1304.  
  1305. ColourTableEntry::~ColourTableEntry(void)
  1306. {
  1307.   delete[] name;
  1308. }
  1309.  
  1310. void AddColour(char *theName, unsigned int r,  unsigned int g,  unsigned int b)
  1311. {
  1312.   wxNode *node = ColourTable.Find(theName);
  1313.   if (node)
  1314.   {
  1315.     ColourTableEntry *entry = (ColourTableEntry *)node->Data();
  1316.     if (entry->red == r || entry->green == g || entry->blue == b)
  1317.       return;
  1318.     else
  1319.     {
  1320.       delete entry;
  1321.       delete node;
  1322.     }
  1323.   }
  1324.   ColourTableEntry *entry = new ColourTableEntry(theName, r, g, b);
  1325.   ColourTable.Append(theName, entry);
  1326. }
  1327.  
  1328. int FindColourPosition(char *theName)
  1329. {
  1330.   int i = 0;
  1331.   wxNode *node = ColourTable.First();
  1332.   while (node)
  1333.   {
  1334.     ColourTableEntry *entry = (ColourTableEntry *)node->Data();
  1335.     if (strcmp(theName, entry->name) == 0)
  1336.       return i;
  1337.     i ++;
  1338.     node = node->Next();
  1339.   }
  1340.   return -1;
  1341. }
  1342.  
  1343.   
  1344. void InitialiseColourTable(void)
  1345. {
  1346.   // \\red0\\green0\\blue0;
  1347.   AddColour("black", 0,0,0);
  1348.  
  1349.   // \\red0\\green0\\blue255;\\red0\\green255\\blue255;\n");
  1350.   AddColour("cyan", 0,255,255);
  1351.  
  1352.   // \\red0\\green255\\blue0;
  1353.   AddColour("green", 0,255,0);
  1354.   
  1355.   // \\red255\\green0\\blue255;
  1356.   AddColour("magenta", 255,0,255);
  1357.  
  1358.   // \\red255\\green0\\blue0;
  1359.   AddColour("red", 255,0,0);
  1360.   
  1361.   // \\red255\\green255\\blue0;
  1362.   AddColour("yellow", 255,255,0);
  1363.   
  1364.   // \\red255\\green255\\blue255;}");
  1365.   AddColour("white", 255,255,255);
  1366. }
  1367.  
  1368. /*
  1369.  * The purpose of this is to reduce the number of times wxYield is
  1370.  * called, since under Windows this can slow things down.
  1371.  */
  1372.  
  1373. static int yieldCount = 0;
  1374.  
  1375. void Tex2RTFYield(Bool force)
  1376. {
  1377. #ifdef wx_msw
  1378.   if (isSync)
  1379.     return;
  1380.     
  1381.   if (force)
  1382.     yieldCount = 0;
  1383.   if (yieldCount == 0)
  1384.   {
  1385.     wxYield();
  1386.     yieldCount = 10;
  1387.   }
  1388.   yieldCount --;
  1389. #endif
  1390. }
  1391.  
  1392.